<?php

namespace App\Jobs\Plane\PlaneOrder;

use App\Events\Plane\PlaneOrder\PlaneOrderTicketFailedEvent;
use App\Exceptions\Plane\Order\PlaneOrderStockNotEnoughException;
use App\Exceptions\Plane\Order\PlaneTicketFailedException;
use App\Exceptions\Plane\PlaneQueryStockNotEnoughException;
use App\Exceptions\Plane\ProviderCantPayException;
use App\Jobs\Middleware\RateLimited;
use App\Models\Plane\PlaneOrders\PlaneOrder;
use App\Models\Plane\PlaneOrders\Repositories\Interfaces\PlaneOrderRepositoryInterface;
use App\Models\Trip\OrderPay\OrderPay;
use App\Notifications\OrderNeedManualHandleNotify;
use App\Trip\Enums\Plane\PlaneProviders;
use App\Trip\Orders\TripOrderState;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class ProcessAfterPlaneOrderPaid implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private PlaneOrder $order;
    private OrderPay   $orderPay;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(PlaneOrder $order, OrderPay $orderPay)
    {
        $this->order    = $order;
        $this->orderPay = $orderPay;

    }

    /**
     * Execute the job.
     *
     * @return void
     * @throws Exception|GuzzleException
     */
    public function handle()
    {

        $order_service = $this->order->order_service;
        Log::info("飞机票订单支付后业务:{$order_service}:{$this->order->order_sn}");
        $service              = PlaneProviders::from($order_service)->getPlaneOrderStrategy();
        $order                = $this->order;
        $order_pay            = $this->orderPay;
        $planeOrderRepository = app(PlaneOrderRepositoryInterface::class);
        if ($order->isCancel()) {
            Log::info("飞机票支付成功后回调,订单已取消,order_sn:{$order->getOrderSn()},out_order_sn:{$order->getOutOrderSn()}");
            return;
        }

        if ($order->pay_state != 1) {
            Log::error("飞机票订单支付状态,不为已支付,无法继续操作,当前支付状态:{$order->pay_state}");
            return;
        }

        switch ($order->getOrderState()) {
            case TripOrderState::ORDER_STATE_PAID:
                // 执行 机票支付操作
                $out_order_id = $order->getOutOrderId();
                $res          = $service->before_pay_validate([
                    'out_order_id' => $out_order_id,
                    'order_info'   => $order,
                ]);
                if ($res->canPay()) {
                    // 如果未支付 发起支付
                    try {
//                        $order_detail = $service->order_detail($out_order_id);
//                        if ($order_detail->canPay()) {
                        $pay_re = $service->book_pay($order);
                        $planeOrderRepository->updateProviderPayState($order, 1, '');
                        Log::info("飞机票支付成功后回调,服务商支付成功,out_order_id:{$out_order_id},out_order_sn:{$order->getOutOrderSn()}");
//                        } else {
//                            // 不能支付 需要微信退款
//                            $planeOrderRepository->updateProviderPayState($order, 2, '供应订单状态不可支付');
//                            Log::info("飞机票支付成功后回调,不能支付,out_order_id:{$out_order_id},out_order_sn:{$order->getOutOrderSn()},status:{$order_detail->getOrderStatus()}");
//                        }
                    } catch (ProviderCantPayException $e) {
                        Log::error("飞机票订单,服务商支付失败,需要查询订单具体情况:{$out_order_id},{$e->getMessage()},{$e->getCode()}");
                        $planeOrderRepository->updateProviderPayState($order, 4, "支付异常,code:{$e->getCode()},需要排查具体情况");
                        throw  new ProviderCantPayException($e->getMessage());
                    } catch (PlaneQueryStockNotEnoughException|PlaneOrderStockNotEnoughException $e) {
                        // 51book de 异常目前无法区分
                        Log::error("飞机票订单,库存不足,服务商支付失败:{$out_order_id},{$e->getMessage()},{$e->getCode()}");
                        $planeOrderRepository->updateProviderPayState($order, 2, '余票不足');
                        throw  new PlaneOrderStockNotEnoughException($e->getMessage());
                    } catch (Exception $e) {
                        Log::error("飞机票订单,服务商支付失败:{$out_order_id},{$e->getMessage()},{$e->getCode()}");
                        $planeOrderRepository->updateProviderPayState($order, 3, "支付异常,code:{$e->getCode()},重试");
                        throw  new PlaneTicketFailedException($e->getMessage());
                    }
                } else {
                    Log::error("飞机票订单,服务商支付失败:{$out_order_id},不能支付");
                    $planeOrderRepository->updateProviderPayState($order, 1, '供应商已支付,无需支付');
                    throw  new ProviderCantPayException('供应商已支付,无需支付');
                }
                break;
            case TripOrderState::ORDER_STATE_CHANGING:
                if ($order->isChangeNew()) {
                    // 可以一起提交
                    $origin_order_info = $planeOrderRepository->getOrderInfo($order->getOriginOrderSn());
                    // 新改签订单距起飞时间不足4小时,
                    $hour = 4;
                    if (Carbon::parse($order->getTripDate())->diffInHours() > $hour) {
                        $changeRes = $service->change_apply($order);
                        if (!$changeRes->isSuccess()) {
                            // 申请失败 走改签失败接口
                            // TODO 某些情况要发短信 如：您所操作订单需使用预留航司手机号联系航司操作改签
                            Log::error("机票改签申请失败：{$order->getOrderSn()},origin:{$order->getOriginOrderSn()}，reason:{$changeRes->failedReason()}");
                            event(new PlaneOrderTicketFailedEvent($order, $order->passengers()->get()->toArray()));
                            return;
                        }
                        // 需支付金额 0 
                        $order->getReceivable() > 0 && $service->change_pay($order, [
                            'totalAmount'           => $order->getReceivable(),
                            'out_order_sn'          => $order->passengers->value('sub_out_order_id'),
                            'out_change_id'         => $order->passengers->value('out_change_id'),
                            'provider_passenger_id' => $order->passengers->pluck('provider_passenger_id')->toArray(),
                        ]);
                    } else {
                        // 发送短信
                        Log::info("变更支付后,需要人工介入处理: {$order->getOrderSn()}");
                        $planeOrderRepository->updateProviderPayState($order, 6, "新改签订单距起飞时间不足{$hour}小时,需人工发起申请");
                        $order->notify(new OrderNeedManualHandleNotify($order->getOrderSn()));
                        return;
                    }
                }
                break;
            default:
                //抢票业务在 TrainSnapPaidListener 中处理
                Log::error("飞机票订单支付成功：{$order->getOrderSn()}，非已支付或已支付待改签:{$order->getOrderState()}");
        }

    }

    /**
     * 任务的唯一 ID。
     *
     * @return string
     */
    public function uniqueId()
    {
        return $this->order->getOrderSn();
    }

    /**
     * 频率限制
     * @return RateLimited[]
     */
    public function middleware()
    {
        return [new RateLimited];
    }
}
